/**
 * 函数类型包含两部分：参数类型和返回值类型。
 * 如果函数没有返回任何值，你也必须指定返回值类型为 void而不能留空。
 */
// 书写完整的函数类型
let myAdd: (baseValue: number, increment: number) => number =
  function (x: number, y: number): number { return x + y; };

// 推断类型 “按上下文归类”，是类型推论的一种
/**
 * 可选参数和默认参数
 * 传递给一个函数的参数个数必须与函数期望的参数个数一致。
 */
function foo(firstName: string, lastName: string) {
  return firstName + lastName;
}
//foo('aa');  // error
//foo('aa','bb','cc'); // error 
foo('aa', 'bb');
//可选参数必须跟在必须参数后面
function fun(firstName: string, lastName?: string) {// 在属性后面跟上?号代表可选参数
  return firstName + lastName;
}
fun('aa');
fun('aa', 'bb');
//fun('aa','bb','cc'); // error
/**
 * 为参数提供默认值
 * 与普通可选参数不同的是，带默认值的参数不需要放在必须参数的后面。
 * 如果带默认值的参数出现在必须参数前面，用户必须明确的传入 undefined值来获得默认值。
 */
function fuc(lastName = 'smit', firstName: string ) {// 在属性后面跟上?号代表可选参数
  return firstName + lastName;
}
//fuc('aa');//error
fuc(undefined,'aa');
fuc('aa', 'bb');
//fuc('aa', 'bb',''); //error

/**
 * 剩余参数
 * 必要，默认，可选参数共同点：他们表示某一个参数
 * 剩余参数：同时操作多个参数
 * 在js中用arguments来访问传递的参数；在ts中，可以把所有参数收集到一个变量中
 */
function restPar(firstName: string, ...restOfName: string[]) { // 注意参数类型的定义
  return firstName + restOfName.join('');
}
restPar("Joseph", "Samuel", "Lucas", "MacKinzie");

